#pragma once

#include <queue>
#include <list>


extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
};

class QFrame
{
public:
    QFrame();
    ~QFrame();

    bool init(int w, int h, int max, enum AVPixelFormat pixFmt)
    {
        m_width = w;
        m_height = h;
        m_maxQueue = max;
        m_pixFmt = pixFmt;
        
        for (int i = 0; i < m_maxQueue; ++i)
        {
            AVFrame* pFrameYUV = av_frame_alloc();
            unsigned char * out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(m_pixFmt, m_width, m_height, 1));
            av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer,
                m_pixFmt, m_width, m_height, 1);
            m_poolFrame.push(pFrameYUV);
        }

        return true;
    }

    bool release()
    {
        while (!m_poolFrame.empty())
        {
            av_frame_free(&m_poolFrame.front());
            m_poolFrame.pop();
        }
        while (!m_cacheFrame.empty())
        {
            av_frame_free(&m_cacheFrame.front());
            m_cacheFrame.pop();
        }
        return true;
    }
    void pushEmptyFrame(AVFrame* back)
    {
        m_poolFrame.push(back);
    }
    AVFrame* takeEmptyFrame()
    {
        AVFrame* ret = NULL;
        
        if (!m_poolFrame.empty())
        {
            ret = m_poolFrame.front();
            m_poolFrame.pop();
        }
        return ret;        
    }
    void pushPicFrame(AVFrame* back)
    {
        m_cacheFrame.push(back);
    }
    AVFrame* takePicFrame()
    {
        AVFrame* ret = NULL;

        if (!m_cacheFrame.empty())
        {
            ret = m_cacheFrame.front();
            m_cacheFrame.pop();
        }
        return ret;
    }

private:
    int m_width{0};
    int m_height{0};
    int m_maxQueue{0};
    enum AVPixelFormat m_pixFmt{};
    
    std::queue<AVFrame*> m_cacheFrame;
    std::queue<AVFrame*> m_poolFrame;
};

